#include "pch.h"
#include "smart_ptr_test.h"

#include <boostext/smart_ptr.hpp>

#ifdef _DEBUG
	#include <mld/mld.hpp>
#endif

using std::string;

using boostext::ref_counted;
using boostext::exclusive;
using boostext::no_check;
using boostext::throw_check;
using boostext::throw_check_strict;
using boostext::heap_storage;
using boostext::heap_array_storage;




void smart_ptr_test::construction()
{
	typedef boostext::smart_ptr<string,ref_counted,no_check> smart_ptr;

	// Test #1: Empty Construction
	{
		smart_ptr p;
		ASSERT(NULL == p.get());
		ASSERT_EQUAL(0, p.refCount());

		smart_ptr p2(p);
		ASSERT_EQUAL(0, p2.refCount());
	}

	// Test #2: Construction from a raw pointer
	{
		smart_ptr p( new string( "test" ) );
		ASSERT( NULL != p.get() );
		ASSERT_EQUAL( 1, p.refCount() );
		ASSERT_EQUAL( "test", *p );
	}

	// Test #3: Copy-construction
	{
		smart_ptr p1( new string( "test" ) );
		smart_ptr p2( p1 );

		ASSERT( p1.get() == p2.get() );
		ASSERT_EQUAL( 2, p1.refCount() );
		ASSERT_EQUAL( 2, p2.refCount() );
		ASSERT_EQUAL( "test", *p1 );
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void smart_ptr_test::assignment()
{
	// We need the no_check policy, otherwise we get assertions
	typedef boostext::smart_ptr<string,ref_counted,no_check> smart_ptr;

	// Test #1: Assignment
	{
		smart_ptr p1( new string("test") );
		smart_ptr p2;

		ASSERT( NULL != p1.get() );
		ASSERT_EQUAL( 1, p1.refCount() );
		ASSERT_EQUAL( (string*)NULL, p2.get() );
		ASSERT_EQUAL( 0, p2.refCount() );

		p2 = p1;
		ASSERT_EQUAL( p1.get(), p2.get() );
		ASSERT_EQUAL( 2, p1.refCount() );
		ASSERT_EQUAL( 2, p2.refCount() );
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void smart_ptr_test::refCounted()
{
	// Exclusive refCounted policy test

	typedef boostext::smart_ptr<bool,ref_counted,no_check> smart_ptr;

	smart_ptr main_ptr_1( new bool( false ) );
	ASSERT_EQUAL( 1, main_ptr_1.refCount() );
	ASSERT_EQUAL( false, *(main_ptr_1.get()) );
	ASSERT_EQUAL( false, *main_ptr_1 );
	{
		smart_ptr main_ptr_2( main_ptr_1 );
		ASSERT_EQUAL( 2, main_ptr_1.refCount() );
		ASSERT_EQUAL( 2, main_ptr_2.refCount() );
		ASSERT_EQUAL( false, *(main_ptr_2.get()) );
		ASSERT_EQUAL( false, *main_ptr_2 );
		{
			smart_ptr main_ptr_3;
			main_ptr_3 = main_ptr_1;
			ASSERT_EQUAL( 3, main_ptr_1.refCount() );
			ASSERT_EQUAL( 3, main_ptr_2.refCount() );
			ASSERT_EQUAL( 3, main_ptr_3.refCount() );
			ASSERT_EQUAL( false, *(main_ptr_3.get()) );
			ASSERT_EQUAL( false, *main_ptr_3 );
		}
		ASSERT_EQUAL( 2, main_ptr_1.refCount() );
		ASSERT_EQUAL( 2, main_ptr_2.refCount() );
	}
	ASSERT_EQUAL( 1, main_ptr_1.refCount() );

	main_ptr_1.release();
	ASSERT_EQUAL( 0, main_ptr_1.refCount() );
	ASSERT_EQUAL( (bool*)NULL, main_ptr_1.get() );
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void smart_ptr_test::exclusive()
{
	typedef boostext::smart_ptr<int,::exclusive,no_check,heap_array_storage> smart_ptr;
	int *ptr = new int[100];

	smart_ptr main_ptr_1( ptr );
	ASSERT_EQUAL( ptr, main_ptr_1.get() );

	smart_ptr main_ptr_2( main_ptr_1 );
	ASSERT_EQUAL( (int*)NULL, main_ptr_1.get() );
	ASSERT_EQUAL( ptr, main_ptr_2.get() );

	// The following code will not compile, because to copy_by_const_ref is false
	// (Copy construction needs a non-const reference)
	//std::vector<smart_ptr> test;
	//test.push_back( main_ptr_1 );
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void smart_ptr_test::throw_check()
{
	typedef boostext::smart_ptr<string,ref_counted,::throw_check> smart_ptr;

	smart_ptr p;
	ASSERT_THROWS( p.get(), boostext::null_pointer_exception );
	ASSERT_THROWS( *p, boostext::null_pointer_exception );
	ASSERT_THROWS( p->size(), boostext::null_pointer_exception );
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void smart_ptr_test::throw_check_strict()
{
	typedef boostext::smart_ptr<string,ref_counted,::throw_check_strict> smart_ptr;

	ASSERT_THROWS( smart_ptr(), boostext::null_pointer_exception );

	// Assignment shall throw as well
	smart_ptr a( new string( "hello" ) );
	ASSERT_THROWS( a = smart_ptr(), boostext::null_pointer_exception );
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void smart_ptr_test::operator()()
{
	construction();
	assignment();

	refCounted();
	exclusive();

	throw_check();
	throw_check_strict();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
